package com.ilongsay.shiro;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.CachingSessionDAO;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;


/**
 * @Author ilongsay
 * @Email ilongsay@163.com
 * @Copyright 版本所有，侵权必究！
 * @Description 这是2.0的版本，继承的是这个CachingSessionDao这个类，避免过于频繁调用
 * @Create 2018-08-15 15:37
 * ①、针对自定义的ShiroSession的redis的crud操作，通过isChanged标识符，确定是否需要调用Update方法
 * ②、通过配置securityManager在属性cacheManager查找从缓存中查找session是否存在，如果找不到才调用下面的方法
 * ③、shiro内部相应的组件（DefaultSecurityManager）会自动检测相应的对象（如Realm）是否实现了CacheManagerAware
 * ④、这里的这个CachingSessionDao已经实现了CacheManagerAware
 */
public class CachingSessionDao extends CachingSessionDAO{

	private static final Logger logger = LoggerFactory.getLogger(CachingSessionDao.class);

	@Autowired
	RedisSessionDao redisSessionDao;

	/**
	 *@author ilongsay
	 *@Createtime 2018-08-15 16:50
	 *@Description 重写了下CachingSessionDao中readSession方法，如果Session方法中没有登录信息就调用
	 * doReadSession方法从Redis中重读
	 * 2.0版本，解决多次调用的问题，优化了代码的实现
	 * @param sessionId
	 *@return org.apache.shiro.session.Session
	 */
	@Override
	public Session readSession(Serializable sessionId) throws UnknownSessionException{
		Session session = getCachedSession(sessionId);
		if (session == null
				|| session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY) == null) {
			session = this.doReadSession(sessionId);
			if (session == null) {
				throw new UnknownSessionException("There is no session with id [" + sessionId + "]");
			} else {
				// 缓存
				cache(session, session.getId());
			}
		}
		return session;

	}

	/**
	 *@author ilongsay
	 *@Createtime 2018-08-17 17:31
	 *@Description 更新缓存中session的值
	 * @param session
	 *@return void
	 */
	@Override
	protected void doUpdate(Session session) {
		try{
			if (session == null || session.getId() == null) {
				System.out.println("Session is null");
				return;
			}
		}catch(Exception e){
			System.out.println("创建session失败");
			e.printStackTrace();
		}finally{

		}

		Serializable sessionId = session.getId();
		redisSessionDao.hadd(sessionId.toString(),session);

	}

	/**
	 *@author ilongsay
	 *@Createtime 2018-08-17 17:27
	 *@Description 删除redi中的session
	  * @param session
	 *@return void
	 */
	@Override
	protected void doDelete(Session session) {
		try{
			if(session == null || session.getId() == null){
				logger.warn("Session的值为空，删除失败");
				return;
			}
			redisSessionDao.hdelete(session.getId().toString());
			logger.debug("Session被删除",session.getId());
		}catch(Exception e){
			logger.warn("删除Session失败",e);
		}finally{

		}
	}

	/**
	 *@author ilongsay
	 *@Createtime 2018-08-20 11:26
	 *@Description 如果是DefaultSessionManager在创建完session后会调用该方法
	 * 如果保存带关系数据库/文件系统/NoSQL数据库，即可实现会话的持久化
	  * @param session
	 *@return java.io.Serializable 返回的是会话的ID；主要是返回ID.equals(session.getId())
	 */
	@Override
	protected Serializable doCreate(Session session) {
		//创建一个id设置给Session
		Serializable sessionId = this.generateSessionId(session);
		assignSessionId(session,sessionId);
		try{
			redisSessionDao.hadd(sessionId.toString(),session);
			logger.info("SessionId{} name {}被创建",sessionId,session.getClass().getName());
		}catch(Exception e){
			logger.warn("创建Session失败",e);
		}finally{

		}
		return sessionId;
	}

	/**
	 *@author ilongsay
	 *@Createtime 2018-08-15 16:52
	 *@Description 根据ID获取session会话，这里还有异常没有捕获
	  * @param sessionId  会话ID
	 *@return org.apache.shiro.session.Session
	 */
	@Override
	protected Session doReadSession(Serializable sessionId) {
		return redisSessionDao.hget(sessionId.toString());
	}
	/**
	 *@author ilongsay
	 *@Createtime 2018-08-17 17:22
	 *@Description 获取session没有设置过期时间
	  * @param sessionId
	 *@return org.apache.shiro.session.Session
	 */
	public Session doReadSessionWithoutExpire(Serializable sessionId){
		return redisSessionDao.hgetWithoutExpire(sessionId.toString());
	}
}
